import { clearRes } from "utils/util";

(function(_super) {
  function Scene() {
    Scene.super(this);
    this.size(Laya.stage.width, Laya.stage.height);
  }
  Laya.class(Scene, "Sail.Scene", _super);
  var _proto = Scene.prototype;

  _proto.onEnter = function() {};
  _proto.onExit = function() {};
  _proto.onResize = function(width, height) {};

  _proto.localToScene = function(ele, point) {
    while (ele) {
      if (ele == this) break;
      point = ele.toParentPoint(point);
      ele = ele.parent;
    }
    return point;
  };

})(Laya.Box);

(function(_super) {
  function SceneManager() {
    SceneManager.super(this);

    this.curScene = null;
    this._scenes = [];
    this._recycle_scenes = [];


    this.init();
  }
  Laya.class(SceneManager, "Sail.SceneManager", _super);
  var _proto = SceneManager.prototype;
  _proto.destroy = function() {
    _super.prototype.destroy.call(this, true);
    this.curScene = null;
  };

  _proto.init = function() {
    this.size(Laya.stage.width, Laya.stage.height);
    this.history = [];
    this.recycle_instance = null;
  };

  _proto.run = function(SceneClass, args, props) {
    var scene;
    if (typeof SceneClass !== 'function') {
      scene = SceneClass;
      SceneClass = scene.SceneClass || scene.constructor;
    }

    if (this.runningClass === SceneClass &&
      !(props && props.reload)) {
      console.warn('runningClass', SceneClass);
      return;
    };

    var curScene = this.curScene;

    if (curScene && !curScene._running) {
      console.error('curScene not mount');
      return;
    }

    props = Object.assign({
      destroy: true,
      history: true
    }, props);

    if (curScene && curScene.onExit) {
      if (props.destroy !== false || props.isBack) {
        curScene.onExit();
      }
    }

    Laya.stage._frameRate = 'fast';

    this.preload(SceneClass, () => {
      if (!scene) {
        if (args && !Array.isArray(args)) {
          args = [args];
        }
        var Constructor = args ? Function.bind.apply(SceneClass, [null].concat(args)) : SceneClass;

        if (
          !props.isBack && props.destroy !== false &&
          curScene && curScene.withoutHistory !== true &&
          curScene.__sceneProps.history !== false
        ) {
          this.history.push({
            SceneClass: curScene.SceneClass,
            props: curScene.__sceneProps,
            args: curScene.__sceneArgs
          });
        }

        if (curScene) {
          this.preSceneClass = curScene.SceneClass;
        }

        scene = new Constructor();
        scene.__sceneProps = props;
        scene.__sceneArgs = args;
        scene.SceneClass = SceneClass;

        SceneClass.instance = scene;
      }

      this.mount(scene, { SceneClass, args, props }, curScene);

      if (SceneClass === Sail.HomeScene) {
        this.clearHistory();
      }

      Sail.io.publish('monitor.sceneChange', { scene, beforeScene: curScene });
    });

  };

  _proto.mount = function(scene, parmas, curScene) {
    let { SceneClass, props } = parmas;

    if (!scene.parent) {
      scene.zOrder = 10;
      this.addChild(scene);
    } else {
      scene.visible = true;
      scene.zOrder = 10;
      this.history.forEach(p => {
        if (p.addChild) {
          p.zOrder = 0;
        }
      });
    }

    if (scene.onResize) {
      scene.onResize(Laya.stage.width, Laya.stage.height);
    }

    if (curScene) {
      if (!props.isBack && props.destroy === false) {
        this.history.push(curScene);
        curScene.removeSelf();
      } else {
        curScene.destroy(true);
        SceneClass.instance = null;

        if (Array.isArray(this.relases_assets)) {
          this.relases_assets.forEach(v => {
            if (v.release) {
              clearRes(v.url);
            }
          });
        }
      }
    }

    this.curScene = scene;
    this.runningClass = SceneClass;


    Laya.timer.callLater(this, function() {
      if (!scene._running) {
        scene._running = true;
        scene.onEnter && scene.onEnter();
      }
      Laya.stage._frameRate = 'slow';

      this.event('SAIL_SCENE_CHANGE', { scene, beforeScene: curScene });

      if (props.onComplete) {
        props.onComplete();
      }
    });
  };

  _proto.preload = function(SceneClass, callback) {
    var SENSE_ASSETS = window.SENSE_ASSETS;
    var taskList = [];
    var ASSET_NAME = Object.keys(SENSE_ASSETS).find(function(className) {
      var SC = className.split('.').reduce((obj, name) => obj[name], window);
      return SC === SceneClass;
    });

    if (ASSET_NAME && SENSE_ASSETS[ASSET_NAME].length > 0) {
      taskList.push(new Promise(resolve => {
        Laya.loader.load(SENSE_ASSETS[ASSET_NAME], Laya.Handler.create(this, function() {
          this.relases_assets = SENSE_ASSETS[ASSET_NAME];
          delete SENSE_ASSETS[ASSET_NAME];
          setTimeout(resolve, 33);
        }));
      }));
    }

    if (SceneClass.beforeEnter) {
      var p = SceneClass.beforeEnter();
      if (p instanceof Promise)
        taskList.push(p);
    }

    if (taskList.length > 0) {
      if (this.curScene && this.curScene.withoutHistory !== true) {
        Sail.showLoading && Sail.showLoading();
      }
      var startTime = Date.now();
      Promise.all(taskList).then(function(values) {
        var t = Math.max(0, 300 - Date.now() + startTime);
        setTimeout(function() {
          if (typeof callback === 'function') callback();
          Sail.hideLoading && setTimeout(Sail.hideLoading, 64);
        }, t);

      });
    } else {
      if (typeof callback === 'function') callback();
    }
  };

  _proto.goBack = function(args) {
    let p = this.popHistory();
    if (!p) {
      if (Sail.HomeScene) this.run(Sail.HomeScene);
      return;
    };

    if (p.addChild) {
      this.mount(p, {
        SceneClass: p.SceneClass,
        props: { history: false, onComplete: null, destroy: true }
      }, this.curScene);
    } else {
      let { SceneClass, props } = p;
      props = Object.assign({}, props, { onComplete: null, isBack: true, destroy: true });
      Laya.timer.callLater(this, function() {
        this.run(SceneClass, args, props);
      });
    }
  };

  _proto.popSceneClass = function(SceneClass) {
    let p = this.history[this.history.length - 1];
    if (p && p.SceneClass === SceneClass) {
      this.history.pop();
    }
  }

  _proto.clearHistory = function() {
    this.history.forEach(p => {
      if (p.addChild) {
        if (this.curScene !== p) {
          p.destroy(true);
          p.SceneClass.instance = null;
        }
      } else {
        p.instance = null;
      }
    });
    this.history = [];
  }

  _proto.popHistory = function() {
    if (this.history.length) {
      let p = this.history.pop();
      if (p.addChild) {
        return p;
      }
      if (p.SceneClass === this.curScene.SceneClass) {
        return this.popHistory();
      }
      return p;
    }
    return null;
  }

  _proto.onResize = function(width, height) {
    this.size(width, height);

    if (this.curScene) {
      this.curScene.size(width, height);
      this.curScene.onResize && this.curScene.onResize(width, height);
    }
  };
})(Laya.Sprite);
